/*
 * File:   mbdef.h
 * Author: aple
 *
 * Created on 2015??8??24??, ????8:38
 * modify @ 20180804
 */

#ifndef __MBDEF_H
#define __MBDEF_H

#ifdef __cplusplus
extern "C"
{
#endif

#include "stdint.h"
#include "dat_quene.h"

/*****************************************************************************
 * @brief   功能开关
 ****************************************************************************/
#ifndef MB_MUL_TASK_EN
#define MB_MUL_TASK_EN 1
#endif

#ifndef MB_TCP_IP_EN
#define MB_TCP_IP_EN 1
#endif

#define MB_BUFF_SIZE (256)
#define MMB_TIMEOUT_DEFAULT_MS (120)

// 计时事件
#define MB_EVENT_RCV_END (0x01)	  // 接收结束
#define MB_EVENT_MMB_READY (0x02) // 主机就绪，空闲延时结束
#define MB_EVENT_TIMEOUT (0x04)	  // 主机等待超时
#define MB_EVENT_SEND_END (0x08)  // 发送结束，暂不用
#define MB_EVENT_NEW_CMD (0x10)	  // 首条指令

// 功能开关
#define MB_FUN_READ_COILS_ENABLED (1)			// fun: 01
#define MB_FUN_READ_DISCRETE_INPUTS_ENABLED (1) // fun: 02
#define MB_FUN_READ_REG_ENABLED (1)				// fun: 03
#define MB_FUN_READ_INPUT_ENABLED (1)			// fun: 04
#define MB_FUN_WRITE_COIL_ENABLED (1)			// fun: 05
#define MB_FUN_WRITE_REG_ENABLED (1)			// fun: 06
#define MB_FUN_WRITE_MULTIPLE_COILS_ENABLED (1) // fun: 15
#define MB_FUN_WRITE_MULTIPLE_REG_ENABLED (1)	// fun: 16
#define MB_FUN_W_R_MULTIPLE_REG_ENABLED (1)		// fun: 0x17

// 数据区开关
#define MB_REG_COILS_CB_ENABLE (MB_FUN_READ_COILS_ENABLED + MB_FUN_WRITE_COIL_ENABLED + MB_FUN_WRITE_MULTIPLE_COILS_ENABLED)
#define MB_REG_HOLDING_CB_ENABLE (MB_FUN_READ_REG_ENABLED + MB_FUN_WRITE_REG_ENABLED + MB_FUN_WRITE_MULTIPLE_REG_ENABLED + MB_FUN_W_R_MULTIPLE_REG_ENABLED)
#define MB_REG_INPUT_CB_ENABLE (MB_FUN_READ_INPUT_ENABLED)
#define MB_REG_DISCRETE_CB_ENABLE (MB_FUN_READ_DISCRETE_INPUTS_ENABLED)

#define MB_COIL_ON 0xFF00
#define MB_COIL_OFF 0x0000

// err msk
#define MB_ERR_CODE_MSK 0x80

// 错误编码
#define MB_ERR_NONE 0		   // 无错误
#define MB_ERR_FUN_CODE 1	   // 非法功能码
#define MB_ERR_NOREG 2		   // 非法数据地址
#define MB_ERR_DATA 3		   // 非法数据值
#define MB_ERR_DEVICE_FAULT 4  // 从设备故障
#define MB_ERR_CONFIRM 5	   // 设备忙时确认-与编程指令配合
#define MB_ERR_BUSY 7		   // 设备忙
#define MB_ERR_PARITY 8		   // 文件奇偶校验错误
#define MB_ERR_NET_PATH 10	   // 网关路径错误
#define MB_ERR_NET_LOST 11	   // 网关目标响应失败
#define MB_ERR_HAL_PARITY 0x40 // 奇偶校验错误

#define MB_ERR_RET_ID 122	// 主机接收到的ID不匹配
#define MB_ERR_RET_CODE 123 // 主机接收到的功能码不匹配
#define MB_ERR_CRC_LRC 124
#define MB_ERR_HAL 125
#define MB_ETIMEDOUT 126
#define MB_ERR_UNKNOWN 127

#define MB_NULL (0)

/*****************************************************************************
 * @brief   基本数据类型
 ****************************************************************************/
#define MB_DAT_TYP_DEF
	typedef unsigned char mb_slave_id_type;
	typedef unsigned short mb_reg_num_type;
	typedef unsigned short mb_reg_addr_type;
	typedef unsigned short mb_reg_data_type;

	typedef union
	{
		uint16_t Val;
		uint16_t uVal;
		int16_t iVal;
		uint16_t uval;
		int16_t ival;
		struct
		{
#ifndef BIG_ENDIAN
			uint8_t LB;
			uint8_t HB;
#else
		uint8_t HB;
		uint8_t LB;
#endif
		} byte;
	} mb_data_type;

/*****************************************************************************
 * @brief   支持的命令列表
 *****************************************************************************/
#define MB_FUN_CODE_LIST

	typedef enum
	{
		FUN_CODE_NONE = 0,
		FUN_CODE_READ_COILS = 0x01,
		FUN_CODE_READ_DISCRETE = 0x02,
		FUN_CODE_READ_REG = 0x03,
		FUN_CODE_READ_INPUT = 0x04,
		FUN_CODE_WRITE_COIL = 0x05,
		FUN_CODE_WRITE_REG = 0x06,
		FUN_CODE_WRITE_MULTIPLE_COIL = 0x0F,
		FUN_CODE_WRITE_MULTIPLE_REG = 0x10,
		FUN_CODE_WRITE_MASK = 0x16,
		FUN_CODE_W_R_MULTIPLE_REG = 0x17,
		FUN_CODE_READ_SLAVE_ID = 0x2B,
		FUN_GUS_REG_WRITE = 0x80, // CRC 校验的开启/关闭由配置文件的 0x2C.6 位控制
		FUN_GUS_REG_READ = 0x81,
		FUN_GUS_PV_WRITE = 0x82,
		FUN_GUS_PV_READ = 0x83,
		FUN_GUS_LINE_WRITE = 0x84,
		FUN_GUS_AUTO = 0xEE, // 无返回数据的自由指令
	} mb_cmd_type;

	/*****************************************************************************
	 * @brief   接收状态定义
	 *****************************************************************************/
	typedef enum
	{
		MB_RX_IDLE,		  // 接收空闲
		MB_RX_RCV,		  // 正在接收
		MB_RX_RCVEND,	  // 接收完成
		MMB_RX_WAIT,	  // 等待接收 - 仅主机
		MMB_RX_NACK_WAIT, // 无需应答 - 仅主机
		MMB_RX_NACK_END,  // 无需应答 - 仅主机
		MB_RX_TIMEOUT,	  // 等待超时 - 仅主机
	} mb_rcv_st_type;

	/*****************************************************************************
	 * @brief   发送状态定义
	 *****************************************************************************/
	typedef enum
	{
		MB_TX_IDLE, // 发送空闲
		MB_TX_XMIT	// 正在发送
	} mb_snd_st_type;

	/*****************************************************************************
	 * @brief   奇偶校验定义
	 *****************************************************************************/
	typedef enum
	{
		MB_PAR_NONE,	// 8N2
		MB_PAR_ODD,		// 8O1
		MB_PAR_EVEN,	// 8E1
		MB_PAR_NONE_1S, // 8N1
	} mb_parity_type;

	/*****************************************************************************
	 * @brief   寄存器读写
	 *****************************************************************************/
	typedef enum
	{
		MB_REG_READ,
		MB_REG_WRITE,
	} mb_reg_mode_type;

	/*****************************************************************************
	 * @brief   工作模式定义
	 *****************************************************************************/
	typedef enum
	{
		MB_RTU_MASTER,	   // 串口RTU主机/客户机
		MB_RTU_SLAVE,	   // 串口RTU从机/服务器
		MB_ASCII_MASTER,   // 串口ASC主机/客户机
		MB_ASCII_SLAVE,	   // 串口ASC从机/服务器
		MB_TCP_MASTER,	   // TCP 主机/客户机
		MB_TCP_SLAVE,	   // TCP 从机/服务器
		MB_TCP_RTU_MASTER, // RTU ON TCP 主机/客户机
		MB_TCP_RTU_SLAVE,  // RTU ON TCP 从机/服务器
	} mb_mode_type;

	/*****************************************************************************
	 * @brief   通用波特率定义
	 *****************************************************************************/
	typedef enum
	{
		MB_BAUD_1200 = 0,
		MB_BAUD_2400 = 1,
		MB_BAUD_4800 = 2,
		MB_BAUD_9600 = 3,
		MB_BAUD_19200 = 4,
		MB_BAUD_38400 = 5,
		MB_BAUD_115200 = 6
	} mb_baud_type;

#define mb_baud_tab_create const uint32_t mb_baud_tab[] = {1200, 2400, 4800, 9600, 19200, 38400, 115200}

	extern const uint32_t mb_baud_tab[];

	/*****************************************************************************
	 * @brief   运行状态
	 *****************************************************************************/
	typedef union
	{
		uint32_t st;

		struct
		{
			uint8_t master_mode : 1;
			uint8_t rtu_mode : 1;
			uint8_t tcp_mode : 1;
			uint8_t port_st;
			uint8_t connect;
		} bits;
	} mb_run_st_type;

	/*****************************************************************************
	 * @brief   错误状态
	 *****************************************************************************/
	typedef union
	{
		uint32_t st;

		struct
		{
			uint8_t hal;
			uint8_t id0_rcv; // receive id 0 in slave mode
		} bits;
	} mb_err_st_type;

	/*****************************************************************************
	 * @brief   运行状态
	 *****************************************************************************/
	typedef struct
	{
		uint16_t head_num;	 // 事务标识符
		uint16_t mb_tcp_num; // 协议标识符
		uint16_t len;		 // PDU长度
		uint8_t sid;		 // 链路标识符
	} mb_tcp_mbap_type;

	/*****************************************************************************
	 * @brief   主机命令结构
	 *****************************************************************************/
	typedef struct
	{
		void *dat;											 // 数据指针
		mb_cmd_type cmd;									 // 命令功能码
		uint8_t device_id;									 // 从站号@RTU/ASC, 链路标识符 @ TCP模式
		uint16_t dat_addr;									 // 数据地址
		uint16_t amount;									 // 数据数量
		void (*call_back)(uint8_t cmd_site, uint8_t err_st); //回调
	} mb_cmd_buff_type;

	/*****************************************************************************
	 * @brief   从机回调接口
	 *****************************************************************************/
	typedef struct
	{
		uint8_t (*reg_input_cb)(uint8_t *buff, uint16_t addr, uint16_t reg_len);
		uint8_t (*reg_hold_cb)(uint8_t *buff, uint16_t addr, uint16_t reg_len, mb_reg_mode_type rw_mode);
		uint8_t (*reg_discrete_cb)(uint8_t *buff, uint16_t addr, uint16_t coils_len);
		uint8_t (*reg_coils_cb)(uint8_t *buff, uint16_t addr, uint16_t coils_len, mb_reg_mode_type rw_mode);
	} smb_fun_type;

	/*****************************************************************************
	 * @brief   主机管理结构
	 *****************************************************************************/
	typedef struct
	{
		com_quene_type dcmd_quene;	// 动态命令队列
		uint8_t err_cnt;			// 错误计数器，发送新命令时自动清除一次
		uint8_t err_sv;				// 错误重发次数设定,默认值为3
		uint8_t cmd_amount;			// 总缓冲池尺寸
		uint8_t cmd_exe_index;		// 当前处理命令索引
		uint8_t scmd_amount;		// 静态缓冲池尺寸
		uint8_t scmd_exe_index;		// 静态命令处理索引
		uint8_t st_cmd_empty;		// 指令空状态
		mb_cmd_buff_type *pcmdBuff; // 指令指针 - 指向主机命令缓冲池
#if MB_MUL_TASK_EN > 0
		void (*mutex_pend)(void);
		void (*mutex_post)(void);
#endif
	} mmb_fun_type;

	/*****************************************************************************
	 * @brief   对象接口
	 *****************************************************************************/
	typedef struct
	{
		void (*rtu_timer_run)(void);
		void (*obj_init)(void);
		void (*mb_poll)(void);
		uint8_t (*os_stc_cmd_req)(uint8_t cmd_site, mb_cmd_buff_type *pcmd);
		uint8_t (*os_dyna_cmd_req)(mb_cmd_buff_type *pcmd);
		uint8_t (*os_stc_cmd_del)(uint8_t cmd_site);
		uint8_t (*stc_cmd_req)(uint8_t cmd_site, mb_cmd_buff_type *pcmd);
		uint8_t (*dyna_cmd_req)(mb_cmd_buff_type *pcmd);
		uint8_t (*stc_cmd_del)(uint8_t cmd_site);
		uint8_t (*cmd_ready_num)(void);
		uint8_t (*cmd_idle_num)(void);
		void (*cmd_clr)(void);
		// hal layer
		void (*rx_read)(uint8_t dat);
		void (*tx_write)(void (*send)(uint8_t), uint8_t len);
		void (*tx_end)(void);
	} mb_fun_interface_type;

	/*****************************************************************************
	 * @brief   对象结构
	 *****************************************************************************/
	typedef struct
	{
		mb_run_st_type run_st;						 // 【X-ST】运行状态
		mb_err_st_type err_st;						 // 【X-ST】错误状态
		mb_rcv_st_type rcv_st;						 // 【X-ST】接收状态
		mb_snd_st_type snd_st;						 // 【X-ST】发送状态
		uint8_t ascii_st;							 // 【X-ST】ascii 模式下字节状态
		uint8_t rtu_timer_cnt;						 // 【X-ST】RTU结束判定计时器，用于软件定时
		uint8_t b_rtu_timer_on;						 // 【X-ST】RTU定时器开启
		uint8_t rtu_timer_sv;						 // 【Y-HAL】RTU结束判定设定值，用于软件定时
		uint8_t st_rcv_end_notice;					 // 【X-ST】RCV END NOTICE
		uint8_t rtu_master_delay_set;				 // 【Y】命令处理延时设定值-仅主机，用于匹配从站速度
		uint8_t id0_ack_en;							 // 【Y】slave id = 0, 是否应答
		uint8_t rtu_len_cut;						 // 【Y】rtu 模式根据功能码截取报文长度
		uint8_t slave_id;							 // 【Y】从机id //仅在从模式设置；主模式由内部管理，禁止应用层修改。从站号@RTU/ASC, 链路标识符 @ TCP模式
		uint16_t os_event_base;						 // 【Y】RTU结束事件值 预设 //使用OS且用内部管理定时器时使用
		uint16_t timeout_set;						 // 【Y-HAL】命令超时时间设定值
		uint16_t timeout_cnt;						 // 【X-ST】本机报文发送结束后开始计时//仅供主机 //应在串口ISR中清除
		uint16_t rcv_cnt;							 // 【X-ST】接收数据个数
		uint16_t snd_size;							 // 【X-ST】待发送数据个数
		uint16_t snd_cnt;							 // 【X-ST】发送过程计数
		uint16_t success_keep_cnt;					 // 【X-CNT】通信成功保持次数
		uint16_t fail_keep_cnt;						 // 【X-CNT】通信失败保持次数
		uint16_t success_cnt;						 // 【X-CNT】通信成功总次数
		uint16_t fail_cnt;							 // 【X-CNT】通信失败总次数
		uint16_t active_keep_cnt;					 // 【X-CNT】活动状态计时 //包括 MB_TX_XMIT MB_RX_RCV
		uint16_t active_keep_max;					 // 【X-CNT】活动状态计时最大值，用于调试监控
		uint16_t idle_time_cnt;						 // 【X-CNT】空闲计时器，RX,TX均为IDLE时计时
		uint16_t sucess_none_time_cnt;				 // 【X-CNT】执行成功后计时，每次成功清除
		void (*adu_send)(void);						 // 【Y-CB】函数指针 - 发送adu_buff数据到端口，数量由snd_size指示
		void (*os_event_send)(uint16_t event);		 // 【Y-CB】使用OS时发送事件
		void (*rcv_end_handle_comp)(uint8_t err_st); // 【Y-CB】报文处理结束回调
		smb_fun_type slave;							 // 【Y-STR】从机结构
		mmb_fun_type master;						 // 【Y-STR】主机结构
		mb_cmd_buff_type mcmd_now[2];				 // 【X-STR】当前正在处理的命令，仅在接收处理时使用。
#if MB_TCP_IP_EN > 0								 //
		uint16_t eth_mmb_head;						 // 【X-STR】当前事务标识符，主机每发送一次递增一次
		mb_tcp_mbap_type eth_snd_mbap;				 // 【X-STR】tcp模式发送标识符
		mb_tcp_mbap_type eth_rcv_mbap;				 // 【X-STR】tcp模式接收标识符
		uint8_t (*eth_connect)(void);				 // 【Y】连接服务器,RET=0表示连接成功,超时才会重连
		uint8_t *adu_buff;							 // 【X】数据缓冲
		uint8_t dat_buff[MB_BUFF_SIZE + 8];			 // 【X】
#else
	uint8_t adu_buff[MB_BUFF_SIZE]; // 【X】数据缓冲
#endif									  //
		const mb_fun_interface_type *api; // 【Y-API】API封装，选用
	} mb_obj_type;

	/*****************************************************************************
	 * @brief   杂项
	 *****************************************************************************/
	typedef struct
	{
		uint8_t check_val_old;
		uint8_t release_time;
		uint8_t press_time;
		uint8_t opt_out;
	} mb_gus_keep_key_t;

	/*****************************************************************************
	 * @brief   处理过程
	 *****************************************************************************/
	/*
		从机：
		RX-IDLE&TX-IDLE -> RX-RCV&TX-IDLE -> RX-RCVEND&TX-IDLE -> RX-IDLE&TX-SEND -> RX-IDLE&TX-IDLE

		主机：
		RX-IDLE&TX-IDLE -> RX-RCV&TX-SEND -> RX-RCV&TX-IDLE -> RX-RCVEND&TX-IDLE -> RX-IDLE&TX-IDLE
	*/

#ifdef __cplusplus
}
#endif

#endif /* __MBDEF_H */
